import Vue from 'vue'

// v-copy 实现复制文本内容
// v-emoji 实现控制表单元素只能输入”数字字母“
~(function () {
  Vue.directive('copy', {
    bind(el, binding) {
      el.$value = binding.value
      el.$handle = function () {
        let text = el.$value
        if (!text) {
          alert('复制内容不能为空！')
          return
        }
        let textarea = document.createElement('textarea')
        textarea.value = text
        textarea.readonly = 'readonly'
        // display这个不可以
        // textarea.display = 'none';
        textarea.style.cssText = 'opacity:0;position:fixed;left:-99999px'
        document.body.appendChild(textarea)

        textarea.select()
        let copyText = document.execCommand('Copy')

        if (copyText) {
          // todo...
          alert('复制成功！')
        } else {
          alert('复制失败，请重试！')
        }
        // 用完记得移除
        document.body.removeChild(textarea)
      }
      el.addEventListener('click', el.$handle)
    },
    // inserted() { },
    // updated() { },
    componentUpdated(el, binding) {
      el.$value = binding.value
    },
    unbind(el) {
      el.removeEventListener('click', el.$handle)
    }
  })
  /**
   * trigger 触发某个元素的某个时间行为
   * @param {element} el 元素
   * @param {string} type 事件类型
   */
  const trigger = function trigger(el, type) {
    let ev = document.createEvent('HTMLEvents')
    ev.initEvent(type, true, true)
    el.dispatchEvent(ev)
  }
  Vue.directive('emoji', {
    bind(el, binding) {
      el.$handle = () => {
        let val = el.value,
          reg = /[^0-9a-zA-Z]/g
        el.value = val.replace(reg, '')
        // 同步到响应式数据中：v-model原理 触发input事件
        trigger(el, 'input')
      }
      el.addEventListener('keyup', el.$handle)
    },
    unbind(el) {
      el.removeEventListener('keyup', el.$handle)
    }
  })
})()

// v-debounce 防抖
// v-throttle 节流
~(function () {
  // 这两个函数：防抖/节流 摘自lodash源码
  const debounce = function debounce(func, wait, immediate) {
    if (typeof func !== 'function') throw new TypeError('func must be a function!')
    if (typeof wait === 'undefined') {
      wait = 500
      immediate = false
    }
    if (typeof wait === 'boolean') {
      immediate = wait
      wait = 500
    }
    if (typeof immediate === 'undefined') {
      immediate = false
    }
    if (typeof wait !== 'number') throw new TypeError('wait must be a number!')
    if (typeof immediate !== 'boolean') throw new TypeError('immediate must be a boolean!')
    let timer = null,
      result
    return function proxy(...params) {
      let self = this,
        callNow = !timer && immediate
      if (timer) clearTimeout(timer)
      timer = setTimeout(() => {
        clearTimeout(timer)
        timer = null
        if (!immediate) result = func.apply(self, params)
      }, wait)
      if (callNow) result = func.apply(self, params)
      return result
    }
  }
  const throttle = function throttle(func, wait) {
    if (typeof func !== 'function') throw new TypeError('func must be a function!')
    wait = +wait
    if (isNaN(wait)) wait = 300
    let timer = null,
      previous = 0,
      result
    return function proxy(...params) {
      let now = +new Date(),
        remaining = wait - (now - previous),
        self = this
      if (remaining <= 0) {
        if (timer) {
          clearTimeout(timer)
          timer = null
        }
        previous = now
        result = func.apply(self, params)
        return result
      }
      if (!timer) {
        timer = setTimeout(() => {
          clearTimeout(timer)
          timer = null
          previous = +new Date()
          result = func.apply(self, params)
        }, remaining)
      }
      return result
    }
  }
  // 公用配置项
  const config = {
    bind(el, binding) {
      let val = binding.value,
        wait = 500,
        immeidate = false,
        type = 'click',
        params = [],
        func,
        handle = binding.name === 'debounce' ? debounce : throttle
      if (val == null) return
      if (typeof val !== 'function' && typeof val !== 'object') return
      if (binding.arg) wait = +binding.arg
      if (binding.modifiers && binding.modifiers.immediate) immeidate = true
      if (typeof val === 'function') func = val
      if (typeof val === 'object') {
        func = val.func || function () {}
        type = val.type || 'click'
        params = val.params || []
      }

      el.$type = type
      el.$handle = handle(
        function (...args) {
          return func.call(this, ...params.concat(args))
        },
        wait,
        immeidate
      )
      el.addEventListener(el.$type, el.$handle)
    },
    unbind(el) {
      el.removeEventListener(el.$type, el.$handle)
    }
  }
  Vue.directive('debounce', config)
  Vue.directive('throttle', config)
})()

// v-permission
~(function () {
  Vue.directive('permission', {
    inserted(el, binding) {
      // 获取从服务器获取的用户权限列表 Vuex|Storage 「格式:xxx|xxx...」
      let permission = localStorage.getItem('vue2-directive-permission'),
        permissionList = []
      if (!permission) permission = ''
      permissionList = permission.split('|')

      // 获取用户传递的权限校验标识 「格式:xxx|xxx...」
      let passText = binding.value,
        passTextArr = []
      if (!passText) passText = ''
      passTextArr = passText.split('|')

      // 循环校验是否有权限
      let flag = false,
        i = 0,
        len = passTextArr.length
      for (; i < len; i++) {
        if (permissionList.includes(passTextArr[i])) {
          flag = true
          break
        }
      }

      // 控制元素显示隐藏
      if (!flag) el.parentNode && el.parentNode.removeChild(el)
    }
  })
})()

// v-lazyload
~(function () {
  const ob_config = {
    threshold: [1]
  }
  const ob = new IntersectionObserver(entires => {
    // console.log(entires)
    entires.forEach(item => {
      let { target, isIntersecting } = item
      console.log(item)
      if (isIntersecting) {
        target.src = target.$src
        target.style.opacity = 1
        // 用完一定要释放
        ob.unobserve(target)
      }
    })
  }, ob_config)

  Vue.directive('lazyload', {
    inserted(el, binding) {
      console.log('inserted.')
      el.src = ''
      el.style.opacity = 0
      el.style.animation = 'opacity .5s'
      el.$el = el
      el.$src = binding.value
      ob.observe(el)
    }
  })
})()
